#include <FlexiTimer2.h>     // flexitimerライブラリの定義インクルード  https://github.com/wimleers/flexitimer2
#include <FastSPI_LED2.h>    // fastspiライブラリの定義インクルード　https://code.google.com/p/fastspi/

#define  NUM_LEDS  126
#define  DATA_PIN   9

CRGB leds[NUM_LEDS];

CRGB topstarcolor = CRGB::Yellow;

int state = 0;
boolean first = true;

void setup() {
  FlexiTimer2::set(10000, countup);   // タイマー設定（ストップウォッチ設定）
  FlexiTimer2::start();
  FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
  inittree();
  topstar();
}

void onedisp( void (*initfunc)(void), void (*func)(void) ) {
  if (first) {
    (*initfunc)();
    first = false;
  }
  (*func)();
}

void onedisp3( void (*initfunc)(void), void (*func)(int,int,boolean), int arg1, int arg2, boolean arg3 ) {
  if (first) {
    (*initfunc)();
    first = false;
  }
  (*func)(arg1, arg2, arg3);
}

void countup() {
  state++;
  if (state > 42) state = 0;
  first = true;
}

void loop() {
  topstarblink();
//candletree();
//  solidcolor();
//  solidcolorrainbow();
  switch (state) {
    case  0: onedisp3((*allclear), (*colorshower), 1, 2, false);     break;
    case  1: onedisp3((*dummy),    (*randcolorshower), 1, 2, false); break;
    case  2: onedisp3((*dummy),    (*colorshower), 1, 2, true);      break;
    case  3: onedisp3((*dummy),    (*randcolorshower), 1, 2, true);  break;
    case  4: onedisp((*inittree),  (*tree));                         break;
    case  5: onedisp((*dummy),     (*tree));                         break;
    case  6: onedisp3((*allclear), (*colorshower), 1, 0, false);     break;
    case  7: onedisp3((*dummy),    (*randcolorshower), 1, 0, false); break;
    case  8: onedisp3((*dummy),    (*colorshower), 1, 0, true);      break;
    case  9: onedisp3((*dummy),    (*randcolorshower), 1, 0, true);  break;
    case 10: onedisp((*inittree),  (*tree2));                        break;
    case 11: onedisp((*dummy),     (*tree2));                        break;
    case 12: onedisp((*allclear),  (*raindrop));                     break;
    case 13: onedisp((*dummy),     (*raindrop));                     break;
    case 14: onedisp((*allclear),  (*randraindrop));                 break;
    case 15: onedisp((*dummy),     (*randraindrop));                 break;
    case 16: onedisp((*allclear),  (*raindroptogether));             break;
    case 17: onedisp((*inittree),  (*tree3));                        break;
    case 18: onedisp((*dummy),     (*tree3));                        break;
    case 19: onedisp((*allclear),  (*rainbowonelinefast));           break;
    case 20: onedisp((*allclear),  (*rainbowonelineslow));           break;
    case 21: onedisp((*inittree),  (*candletree));                   break;
    case 22: onedisp((*dummy),     (*candletree));                   break;
    case 23: onedisp((*allclear),  (*rainbowtogetherslow));          break;
    case 24: onedisp((*dummy),     (*rainbowtogetherfast));          break;
    case 25: onedisp((*inittree),  (*tree));                         break;
    case 26: onedisp((*dummy),     (*tree));                         break;
    case 27: onedisp3((*allclear), (*colorrise), 1, 2, false);       break;
    case 28: onedisp3((*dummy),    (*randcolorrise), 1, 2, false);   break;
    case 29: onedisp3((*dummy),    (*colorrise), 1, 0, false);       break;
    case 30: onedisp3((*dummy),    (*randcolorrise), 1, 0, false);   break;
    case 31: onedisp((*inittree),  (*tree2));                        break;
    case 32: onedisp((*dummy),     (*tree2));                        break;
    case 33: onedisp3((*allclear), (*colorrise), 1, 2, true);        break;
    case 34: onedisp3((*dummy),    (*randcolorrise), 1, 2, true);    break;
    case 35: onedisp3((*dummy),    (*colorrise), 1, 0, true);        break;
    case 36: onedisp3((*dummy),    (*randcolorrise), 1, 0, true);    break;
    case 37: onedisp((*inittree),  (*tree3));                        break;
    case 38: onedisp((*dummy),     (*tree3));                        break;
    case 39: onedisp((*allclear),  (*solidcolor));                   break;
    case 40: onedisp((*allclear),  (*solidcolorrainbow));            break;
    case 41: onedisp((*inittree),  (*candletree));                   break;
    case 42: onedisp((*dummy),     (*candletree));                   break;
  }
  
}

void allclear() {
  for (int i = 0; i < 120; i++)
    leds[i] = CRGB::Black;
  FastLED.show();
}

void dummy(void) {
}

void topstar() {
  for (int i = 120; i < 126; i++)
    leds[i] = topstarcolor;
}

void topstarblink() {
static int bright = 0;
static boolean up = true;
  if (up) {
    bright += 10;
    if (bright > 255) {
      bright = 255;
      up = false;
    }
  } else {
    bright -= 10;
    if (bright < 0) {
      bright = 0;
      up = true;
    }
  }
  for (int i = 120; i < 126; i++) {
    leds[i] = topstarcolor;
    leds[i].fadeLightBy(bright);
  }
}

void wholeshift() {
  for (int i = 119; i > 0; i--)
    leds[i] = leds[i-1];
}

void eachlineshift() {
  for (int i = 0; i < 5; i++)
    onelineshiftdown(i);
}

void eachlineshiftup() {
  for (int i = 0; i < 5; i++)
    onelineshiftup(i);
}

void eachlinedimmershift() {
  for (int i = 0; i < 5; i++)
    onelinedimmershiftdown(i);
}

void eachlinedimmershiftup() {
  for (int i = 0; i < 5; i++)
    onelinedimmershiftup(i);
}

void onelineshiftdown(int line) {
  for (int i = line * 24 + 23; i > line * 24; i--)
   leds[i] = leds[i-1];
}

void onelineshiftup(int line) {
  for (int i = line * 24; i < line * 24 + 23; i++)
    leds[i] = leds[i+1];
}

void onelinedimmershiftdown(int line) {
int pos = line * 24 + 23;
int dim = 0;
  while (pos > line * 24) {
    leds[pos] = leds[pos-1];
    leds[pos].fadeToBlackBy(dim++ * 2.4);
    pos--;
  }
}
    
void onelinedimmershiftup(int line) {
int pos = line * 24;
int dim = 0;
  while (pos < line * 24 + 23) {
    leds[pos] = leds[pos+1];
    leds[pos].fadeToBlackBy(dim++ * 2.4);
    pos++;
  }
}
    
CRGB basiccolor(int col) {
  CRGB ret;
  switch ( col ) {
  case 0:
    ret = CRGB(255,0,0);
    break;
  case 1:
    ret = CRGB(0,255,0);
    break;
  case 2:
    ret = CRGB(0,0,255);
    break;
  case 3:
    ret = CRGB(128,128,0);
    break;
  case 4:
    ret = CRGB(0,128,128);
    break;
  case 5:
    ret = CRGB(128,0,128);
    break;
  case 6:
    ret = CRGB(255,255,255);
    break;
  }
  return( ret );
}

CRGB doublecolor(int col) {
  CRGB ret;
  switch ( col ) {
  case 0:
    ret = CRGB(255,0,0);
    break;
  case 1:
    ret = CRGB(0,255,0);
    break;
  case 2:
    ret = CRGB(0,0,255);
    break;
  case 3:
    ret = CRGB(128,128,0);
    break;
  case 4:
    ret = CRGB(0,128,128);
    break;
  case 5:
    ret = CRGB(128,0,128);
    break;
  case 6:
    ret = CRGB(170,85,0);
    break;
  case 7:
    ret = CRGB(85,170,0);
    break;
  case 8:
    ret = CRGB(0,170,85);
    break;
  case 9:
    ret = CRGB(0,85,170);
    break;
  case 10:
    ret = CRGB(170,0,85);
    break;
  case 11:
    ret = CRGB(85,0,170);
    break;
  case 12:
    ret = CRGB(255,255,255);
    break;
  }
  return( ret );
}

